const crypto = require('crypto')
const xml2js = require('xml2js')
const moment = require('moment')
const Ajv = require('ajv')
const localize = require('ajv-i18n')

/**
 * 随机字符串
 */
exports.nonceStr = function (length) {
  var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  var maxPos = chars.length
  var noceStr = ''
  for (var i = 0; i < (length || 32); i++) {
    noceStr += chars.charAt(Math.floor(Math.random() * maxPos))
  }

  // Math.random().toString(36).substr(2, 15)

  return noceStr
}

// 随机数
exports.random = function (length) {
  var chars = '0123456789'
  var maxPos = chars.length
  var noceStr = ''
  for (var i = 0; i < (length || 6); i++) {
    noceStr += chars.charAt(Math.floor(Math.random() * maxPos))
  }
  return noceStr
}

// 商户订单号
exports.outTradeNo = function () {
  return moment().format('YYMMDD') + Math.random().toString().substr(2, 8)
}

// 签名生成
// 签名算法https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
exports.sign = function (obj, out, signType = 'md5') {
  // MD5
  if ((signType = 'md5')) {
    var key = obj.key

    ;['key', 'pfx', 'sign'].forEach(function (k) {
      delete obj[k]
    })

    var stringSignTemp = ''
    for (var k of Object.keys(obj).sort()) {
      stringSignTemp += k + '=' + obj[k] + '&'
    }

    // console.log('签名生成', stringSignTemp + 'key=' + key);

    return md5(stringSignTemp + 'key=' + key).toUpperCase()
  }
}

/**
 * JS-SDK签名算法
 *
 * @param Object data 签名数据
 * @param String url 用于签名的 url ，注意必须动态获取，不能 hardcode
 *
 * @returns
 */
exports.jsSdkSign = function (data, url) {
  let signStr = ''
  for (let key of Object.keys(data).sort()) {
    const val = data[key]
    if (signStr != '') signStr += '&'
    signStr += `${key}=${val}`
  }

  console.log('signStr', signStr)

  return sha1(signStr)
}

exports.md5 = md5

// 对象转XML
exports.buildXML = function (json) {
  var builder = new xml2js.Builder()
  return builder.buildObject({
    xml: json,
  })
}

// XML转对象
exports.parseXML = async function (xml) {
  return new Promise((resolve, reject) => {
    var parser = new xml2js.Parser({
      trim: true,
      explicitArray: false,
      explicitRoot: false,
    })

    parser.parseString(xml, function (err, result) {
      if (err) return reject(err)

      return resolve(result)
    })
  })
}

// 时间戳
exports.timeStamp = function timeStamp() {
  return Math.round(new Date().getTime() / 1000)
}

/**
 * 数据验证
 */
exports.ajv = (data, schema, alloweThrow = true, allErrors) => {
  const ajv = Ajv({ allErrors })
  const validate = ajv.compile(schema)
  const valid = validate(data)

  if (!valid) {
    localize.zh(validate.errors)

    const error = ajv.errorsText(validate.errors, { separator: '\n' })

    if (alloweThrow) {
      throw error
    }

    return error
  }
}

function md5(str) {
  str = str + ''
  let crypto_md5 = crypto.createHash('md5')
  crypto_md5.update(str, 'utf8') // 编码
  return crypto_md5.digest('hex')
}

function sha1(str) {
  return crypto.createHash('sha1').update(str).digest('hex')
}
